/**
 * 手写promise
 */

const STATUS_PENDING = 'STATUS_PENDING'; //等待
const STATUS_FULFILLED = 'STATUS_FULFILLED';//成功
const STATUS_REJECTED = 'STATUS_REJECTED';//失败

class MyPromise {

    _status = STATUS_PENDING;//初始值
    _value = undefined;
    _reason = undefined;

    //用数组，缓存多次then的回调函数
    _successCallback = [];//缓存回调,用于异步调用
    _failCallback = [];//缓存回调,用于异步调用,

    constructor(executor) {
        try { //处理执行函数的异常
            executor(this.resolve,this.reject)
        } catch (error) {
            this.reject(error)
        }
    }

    resolve = (value) => {
        if (this._status !== STATUS_PENDING) return
        this._status = STATUS_FULFILLED;
        this._value = value;

        while(this._successCallback.length>0) this._successCallback.shift()()//由于添加上来时处理了参数，这里不需要了
    }

    reject = (reason) => {
        if (this._status !== STATUS_PENDING) return
        this._status = STATUS_REJECTED;
        this._reason = reason;

        while(this._failCallback.length>0) this._failCallback.shift()() //由于添加上来时处理了参数，这里不需要了
    }

    then = (successCallback,failCallback) => {
        failCallback = failCallback ? failCallback : (r)=>{throw r} //失败处理，需要throw才能继续抛出去
        successCallback = successCallback ? successCallback:(v)=>v // 成功处理
        //返回一个新的promise对象，新对象的值等于回调函数的返回值
        const p = new MyPromise((resolve,reject)=>{
            if (this._status === STATUS_FULFILLED) {
                setTimeout(()=>{
                    try { //处理then中的异常
                        let x = successCallback(this._value)
                        resolvePromise(p,x,resolve,reject)
                    } catch (error) {
                        reject(error)
                    }
                },0)
            } else if (this._status === STATUS_REJECTED) {
                setTimeout(()=>{//处理rejected状态的情况
                    try { //处理then中的异常
                        let x = failCallback(this._reason)
                        resolvePromise(p,x,resolve,reject)
                    } catch (error) {
                        reject(error)
                    }
                },0)
            } else { //如果还没有执行完，则缓存回调函数
                this._successCallback.push(()=>{
                    //？？？ 这里可以不写setTimeout吗？目前没想到失败的case
                    // setTimeout(()=>{
                        try {
                            let x = successCallback(this._value)
                            resolvePromise(p,x,resolve,reject)
                        } catch (error) {
                            reject(error)
                        }
                    // },0)
                    
                })
                this._failCallback.push(()=>{
                    // ??? 同理同上面，setTimeout吗？目前没想到失败的case
                    try {
                        let x = failCallback(this._reason)
                        resolvePromise(p,x,resolve,reject)
                    } catch (error) {
                        reject(error)
                    }
                });
            }
        })
        return p;
    }

    //需要返回promise，值等于原promise的结果
    //需要注意的是 callback可能是一个异步，需要等它调用完，才能继续finally后面的链式调用
    finally = (callback) => {
        return this.then(v=>{
            return MyPromise.resolve(callback()).then(()=>v)
        },r=>{
            return MyPromise.resolve(callback()).then(()=>{throw r})
        })
    }

    catch = (callback) => {
        return this.then(undefined,callback)
    }

    //返回一个promise对象
    static all = (array) => {
        let result = [];
        let count = 0;//计数，用于执行返回
        return new MyPromise((resolve,reject)=>{

            function pushResult(k,v) {
                result[k] = v;
                count++;
                if (count === array.length) {
                    resolve(result);
                }
            }

            for (let i = 0;i< array.length;i++) {
                //如果是promise对象，则需要把promise的结果返回
                const x = array[i];
                if (x instanceof MyPromise) { //需要区分是普通值，还是promise
                    x.then(v=>{
                        pushResult(i,v);
                    },r=>{
                        reject(r) //错误直接结束
                    })
                } else {
                    pushResult(i,x);
                }
            }
            
            //promise是异步返回的，这里不能直接处理
            // resolve(result)
        })
    }

    static resolve = (v) => {
        if (v instanceof MyPromise) return v; //这里要特殊处理
        return new MyPromise((resolve,reject)=>{
            resolve(v)
        })
    }
}

//处理返回promise的情况
function resolvePromise(p2,x,resolve,reject) {
    if (p2 === x) {
        reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
        return;
    }
    if (x instanceof MyPromise) {
        x.then(resolve,reject)
    } else {
        resolve(x)
    }
}

module.exports = MyPromise;